package blueq.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.AccessController;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

import org.apache.log4j.Logger;

import sun.security.action.GetPropertyAction;

/**
 * 工具类，如字符串处理等常用方法
 * 
 *   
 */
public class Util {
    private static Logger log = Logger.getLogger(Util.class);
    
    public final static NumberFormat NF1 = new DecimalFormat("#");
    public final static NumberFormat NF2 = new DecimalFormat("#");
    public final static NumberFormat NF3 = new DecimalFormat("#");
    public final static NumberFormat NF4 = new DecimalFormat("#");
    public final static NumberFormat NF5 = new DecimalFormat("#");
    public final static NumberFormat NF6 = new DecimalFormat("#");
    
    static {
        NF2.setMinimumIntegerDigits(1);
        NF2.setMinimumIntegerDigits(2);
        NF3.setMinimumIntegerDigits(3);
        NF4.setMinimumIntegerDigits(4);
        NF5.setMinimumIntegerDigits(5);
        NF6.setMinimumIntegerDigits(6);
    }
    
    
    private static String homePath;
    private static String webinfoPath;
    private static String webContextRootPath;
    
    /**
     * 文本内容的行分隔符
     */
    public static final String LINE_SEPARATOR = (String) java.security.AccessController.doPrivileged(
            new sun.security.action.GetPropertyAction("line.separator"));
    
    /**
     * 默认文件编码
     */
    public static final String DEFAULT_FILE_ENCODING = (String)AccessController.doPrivileged(new GetPropertyAction("file.encoding"));
    
    /**
     * 说明：获取Exception的错误信息，如果错误信息为空，返回该Exception的类名
     *    
     * @param e Exception
     * @return String
     *
     */
    public static String getExceptionMsg(Throwable e) {
        return StringUtil.isNullOrWhitespace(e.getMessage()) ? e.getClass().getName() : e.getMessage();
    }
    

    /**
     * 判断传入字符是否是数字
     * 
     * @param c
     * @return
     */
    public static boolean isNumber(char c) {
        boolean isNumber = false;
        if ((int) c >= (int) '0' && (int) c <= '9') {
            isNumber = true;
        }
        return isNumber;
    }
    

    /**
     * 判断传入字符是否是英文字母
     * 
     * @param c
     * @return
     */
    public static boolean isLetter(char c) {
        boolean isLetter = false;
        if (((int) c >= (int) 'a' && (int) c <= (int) 'z')
                || ((int) c >= (int) 'A' && (int) c <= (int) 'Z')) {
            isLetter = true;
        }
        return isLetter;
    }
    

    /**
     * 判断是否是字符或者数字
     * 
     * @param c
     * @return
     */
    public static boolean isLetterOrNumber(char c) {
        return Util.isLetter(c) || Util.isNumber(c);
    }
 
    /**
     * 获取Web应用程序的WEB-INF目录路径，如果获取目录路径失败，返回<code>null</code>
     * 如: /D:/bea/user_projects/domains/base_domain/autodeploy/DBPServer/
     *    
     * @return
     *
     */
    public static String getWEBContextRootPath() {
        if (StringUtil.isEmptyStr(webContextRootPath)) {
            String webInfoPath = getWEBINFPath();
            if (webInfoPath == null) {
                return null;
            }
            
            try {
                webContextRootPath = webInfoPath.substring(0, webInfoPath.lastIndexOf("WEB-INF"));
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                
                webContextRootPath = null;
            }
        }
        return webContextRootPath;
    }
    
    /**
     * 说明：获取Web应用程序的WEB-INF目录路径，如果获取目录路径失败，返回<code>null</code>
     * 如: /D:/bea/user_projects/domains/base_domain/autodeploy/DBPServer/WEB-INF/
     *    
     * @return String
     *
     */
    public static String getWEBINFPath() {
        if (StringUtil.isEmptyStr(webinfoPath)) {
            String homePath = getHomePath();
            if (homePath == null) {
                return null;
            }
            
            try {
                webinfoPath = homePath.substring(0, homePath.lastIndexOf("classes"));
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                
                webinfoPath = null;
            }
        }
        
        return webinfoPath;
    }
    
    /**
     * 说明：获取程序运行的跟目录路径，如果获取目录路径失败，返回<code>null</code>
     * 如: /D:/bea/user_projects/domains/base_domain/autodeploy/DBPServer/WEB-INF/classes/
     * 
     * @return String 程序运行的跟目录路径
     *
     */
    public static String getHomePath() {
        if (StringUtil.isEmptyStr(homePath)) {
            String path = Util.class.getClassLoader().getResource("home.txt").getPath();
            if (log.isDebugEnabled()) {
                log.debug("Util.class.getClassLoader().getResource(home.txt).getPath(): " + path);
            }
            String returnPath = null;
            try {
                //处理包含中文名的路径
                path = URLDecoder.decode(path, "utf-8");
            } catch (UnsupportedEncodingException e) {
                log.error(e.getMessage(), e);
            }
            if (path.indexOf(".jar") != -1) {
                //用于处理class文件被封装成jar包的情况
                int jarIndex = path.indexOf("jar");
                int firstIndex = 0, secondIndex;
                secondIndex = path.indexOf("/", firstIndex);
                //定位.jar目录
                while (firstIndex < jarIndex) {
                    if (secondIndex > jarIndex) {
                        returnPath = path.substring(0, firstIndex);
                        if (returnPath.indexOf("file:") != -1) {
                            returnPath = returnPath.substring(returnPath.indexOf("file:") + "file:".length());
                        }
                        break;
                    } else {
                        firstIndex = secondIndex + 1;
                        secondIndex = path.indexOf("/", firstIndex);
                    }
                }
            } else {
                returnPath = path.substring(0, path.indexOf("home.txt"));
            }
            
            if (returnPath == null) {
                log.error("Error: com.ydtf.dmis2.common.Util.getHomePath(), Path: " + path);
            }
            if (log.isDebugEnabled()) {
                log.debug("com.ydtf.dmis2.common.Util.getHomePath(), Path: " + returnPath);
            }
            
            homePath = returnPath;
        }
        return homePath;
    }
    
    /**
     * 说明：生成一个32位的通用唯一识别码 (Universally Unique Identifier)
     * 
     * @return String
     */
    public static String getUUID() {
        String uuid = UUID.randomUUID().toString();
        return uuid.replaceAll("-", "");
    }
    
    /**
     * 说明：生成一个36位的通用唯一识别码 (Universally Unique Identifier)
     * 
     * @return
     *
     */
    public static String getUUID36() {
        return UUID.randomUUID().toString();
    }
    
    /**
     * 返回输入日期是本季度的第几天，季度第一天返回1
     * 
     * @param date
     * @return int
     */
    public static int getDayOfQuarter(Date date) {
        final int quarter1 = 1;
        final int quarter2 = 91;
        final int quarter3 = 182;
        final int quarter4 = 274;
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayOfYear = cal.get(Calendar.DAY_OF_YEAR);
        if (dayOfYear >= quarter4) {
            return dayOfYear - quarter4 + 1;
        } else if (dayOfYear >= quarter3) {
            return dayOfYear - quarter3 + 1;
        } else if (dayOfYear >= quarter2) {
            return dayOfYear - quarter2 + 1;
        } else if (dayOfYear >= quarter1) {
            return dayOfYear - quarter1 + 1;
        }
        
        throw new RuntimeException("Util.getDayOfQuarter()程序错误。");
    }
    
    /**
     * 说明：得到指定月份最大天数。
     * 
     * @param month int,参见java.util.Calendar.java月份定义
     * @return int
     *
     * @see java.util.Calendar#JANUARY
     * @see java.util.Calendar#FEBRUARY
     * @see java.util.Calendar#MARCH
     * @see java.util.Calendar#APRIL
     * @see java.util.Calendar#MAY
     * @see java.util.Calendar#JUNE
     * @see java.util.Calendar#JULY
     * @see java.util.Calendar#AUGUST
     * @see java.util.Calendar#SEPTEMBER
     * @see java.util.Calendar#OCTOBER
     * @see java.util.Calendar#NOVEMBER
     * @see java.util.Calendar#DECEMBER
     */
    public static int getMaxDayOfMonth(int month) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.MONTH, month + 1);
        cal.set(Calendar.DAY_OF_MONTH, 0);
        return cal.get(Calendar.DAY_OF_MONTH);
    }
    
    /**
     * 说明：对SQL字符串的特殊字符进行替换
     * 
     * @param sql
     * @return
     */
    public static String sqlEncode(String sql) {
        return sql.replaceAll("'", "''");
    }
    
    /**
     * 说明：将ISO-8859-1编码的字符串转换成GBK编码的字符串
     * 
     * @param str
     * @return
     * @throws Exception
     */
    public static String toGBK(String str) throws Exception {
        return  encodingConvert(str, "ISO-8859-1", "gbk");
    }
    
    /**
     * 说明：如果编码信息为<code>null</code>，启用系统默认编码
     *    
     * @param str 源字符串
     * @param srcEncoding 源字符串编码
     * @param targetEncoding 转换目标编码
     * @return
     */
    public static String encodingConvert(String str, String srcEncoding, String targetEncoding) {
        if (str == null) {
            return str;
        }

        if (srcEncoding == null) {
            srcEncoding = System.getProperty("file.encoding");
        }
        if (targetEncoding == null) {
            targetEncoding = System.getProperty("file.encoding");
        }
        try {
            return new String(str.getBytes(srcEncoding), targetEncoding);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return str;
    }
    
    /**
     * 说明：将字符串进行html编码，对<, >, &, \, ', \n, 空格  进行转义
     *    
     * @param str
     * @return
     */
    public static String htmlEncode(String str) {
        if (str != null) {
            str = str.replaceAll("<", "%lt;").replaceAll(">", "%gt;");
            str = str.replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
            str = str.replaceAll("\n", "<br>").replaceAll(" ", "&nbsp;");
        }
        return str;
    }
    
    /**
     * 说明：将Java的时间格式转换成Oracle的时间格式
     * 
     * @param javaDatePattern
     * @return
     */
    public static String java2OracleDatePattern(String javaDatePattern) {
        javaDatePattern = javaDatePattern.replace("mm", "mi");
        javaDatePattern = javaDatePattern.replace("HH", "hh24");
        
        return javaDatePattern;
    }
    
    /**
     * 说明：将longValue转换成byte数组，第一个字节为高8位。
     * 
     * @param longValue
     * @param buf
     * @param off
     * @return
     */
    public static void long2Bytes(long longValue, byte[] buf, int off) {
        buf[off + 0] = (byte) (longValue >>> 56);
        buf[off + 1] = (byte) (longValue >>> 48);
        buf[off + 2] = (byte) (longValue >>> 40);
        buf[off + 3] = (byte) (longValue >>> 32);
        buf[off + 4] = (byte) (longValue >>> 24);
        buf[off + 5] = (byte) (longValue >>> 16);
        buf[off + 6] = (byte) (longValue >>> 8);
        buf[off + 7] = (byte) longValue;
    }
    
    /**
     * 说明：将longValue转换成byte数组，第一个字节为高8位。
     * 
     * @param longValue
     * @return
     */
    public static byte[] long2Bytes(long longValue) {
        byte[] bytes = new byte[8];
        long2Bytes(longValue, bytes, 0);
        return bytes;
    }

    /**
     * 说明：将bytes数组转换成long值，第一个字节为高8位。
     *    
     * @param bytes
     * @param off
     * @return
     */
    public static long bytes2Long(byte[] bytes, int off) {
        long longValue = bytes[off + 7] & 0xff;
        longValue |= (((long) (bytes[off + 6] & 0xff)) << 8);
        longValue |= (((long) (bytes[off + 5] & 0xff)) << 16);
        longValue |= (((long) (bytes[off + 4] & 0xff)) << 24);
        longValue |= (((long) (bytes[off + 3] & 0xff)) << 32);
        longValue |= (((long) (bytes[off + 2] & 0xff)) << 40);
        longValue |= (((long) (bytes[off + 1] & 0xff)) << 48);
        longValue |= (((long) (bytes[off] & 0xff)) << 56);
        return longValue;
    }
    
    /**
     * 说明：将bytes数组转换成long值，第一个字节为高8位。
     * 
     * @param bytes
     * @return
     */
    public static long bytes2Long(byte[] bytes) {
        return bytes2Long(bytes, 0);
    }
    
    /**
     * 说明：将intValue转换成byte数组，第一个字节为高4位。
     * 
     * @param intValue
     * @param buf
     * @param off
     * @return
     */
    public static void int2Bytes(int intValue, byte[] buf, int off) {
        buf[off] = (byte) (intValue >>> 24);
        buf[off + 1] = (byte) (intValue >>> 16);
        buf[off + 2] = (byte) (intValue >>> 8);
        buf[off + 3] = (byte) intValue;
    }
    
    /**
     * 说明：将intValue转换成byte数组，第一个字节为高4位。
     *    
     * @param intValue
     * @return
     */
    public static byte[] int2Bytes(int intValue) {
        byte[] bytes = new byte[4];
        int2Bytes(intValue, bytes, 0);
        return bytes;
    }

    /**
     * 说明：将bytes数组转换成int值，第一个字节为高8位。
     * 
     * @param bytes
     * @param off
     * @return
     */
    public static int bytes2Int(byte[] bytes, int off) {
        int intValue = bytes[off + 3] & 0xff;
        intValue |= ((bytes[off + 2] & 0xff) << 8);
        intValue |= ((bytes[off + 1] & 0xff) << 16);
        intValue |= ((bytes[off] & 0xff) << 24);
        return intValue;
    }
    
    /**
     * 说明：将bytes数组转换成int值，第一个字节为高8位。
     * 
     * @param bytes
     * @return
     */
    public static int bytes2Int(byte[] bytes) {
        return bytes2Int(bytes, 0);
    }
    
    /**
     * 说明：以“yyyy-MM-dd HH:mm:ss”为时间格式，解析时间字符串
     * 
     * @param date
     * @return
     */
    public static Date parseDate(String date) {
        return parseDate(date, "yyyy-MM-dd HH:mm:ss");
    }
    
    /**
     * 说明：按指定的格式,解析时间字符串
     * 
     * @param date
     * @param pattern
     * @return
     */
    public static Date parseDate(String date, String pattern) {
        DateFormat df = new SimpleDateFormat(pattern);
        try {
            return df.parse(date);
        } catch (ParseException e) {
            return null;
        }
    }
    
    /**
     * 说明：以“yyyy-MM-dd HH:mm:ss”为时间格式，格式化时间
     *    
     * @param date
     * @return
     */
    public static String formatDate(Date date) {
        return formatDate(date, "yyyy-MM-dd HH:mm:ss");
    }
    
    /**
     * 说明：按指定的格式,格式化时间
     *    
     * @param date
     * @param pattern
     * @return
     */
    public static String formatDate(Date date, String pattern) {
        DateFormat df = new SimpleDateFormat(pattern);
        return df.format(date);
    }
    
    /**
     * 说明：根据偏移字符串参数的定义，返回一个相对的当前时间。
     * 例子：
     * 1.返回当前时间的偏移字符串：y=0,M=0,d=0,h=0,m=0,s=0（或者是一个空白字符串）
     * 2.返回当前时间上一天的偏移字符串：y=0,M=0,d=-1,h=0,m=0,s=0
     * 3.返回当前时间下一天的偏移字符串：y=0,M=0,d=1,h=0,m=0,s=0
     *    
     * @param pattern 日期的格式
     * @param offString 格式："y=0,M=0,d=0,h=0,m=0,s=0"
     * @return
     */
    public static String getCurrentDate(String pattern, String offString) {
        DateFormat df = new SimpleDateFormat(pattern);
        Calendar cal = Calendar.getInstance();
        if (!StringUtil.isNullOrWhitespace(offString)) {
            String[] elements = offString.split(",");
            for (int i = 0; i < elements.length; i++) {
                if (!StringUtil.isNullOrWhitespace(elements[i])) {
                    String[] elt = elements[i].split("=");
                    char field = elt[0].trim().charAt(0);
                    int value = Integer.parseInt(elt[1].trim());
                    
                    switch (field) {
                        case 'y':
                            cal.add(Calendar.YEAR, value);
                            break;
                        case 'M':
                            cal.add(Calendar.MONTH, value);
                            break;
                        case 'd':
                            cal.add(Calendar.DATE, value);
                            break;
                        case 'h':
                            cal.add(Calendar.HOUR, value);
                            break;
                        case 'm':
                            cal.add(Calendar.MINUTE, value);
                            break;
                        case 's':
                            cal.add(Calendar.SECOND, value);
                            break;
                        default:
                            throw new RuntimeException("当前时间的偏移量无法识别：" + field);
                    }
                }
            }
        }
        
        return df.format(cal.getTime());
    }
    
    public static String getCurrentWeekBegin(String pattern) {
        DateFormat df = new SimpleDateFormat(pattern);
        Calendar cal = Calendar.getInstance();
        DateFormat dfWeek = new SimpleDateFormat("yyyyMMdd");
        try {
            cal.setTime(dfWeek.parse(dfWeek.format(cal.getTime())));//剔除日以下的时间
            cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        } catch (ParseException e) {
            log.error(getExceptionMsg(e), e);
            throw new RuntimeException(e);
        }
        return df.format(cal.getTime());
    }
    
    public static String getCurrentMonthBegin(String pattern) {
        DateFormat df = new SimpleDateFormat(pattern);
        Calendar cal = Calendar.getInstance();
        DateFormat dfWeek = new SimpleDateFormat("yyyyMMdd");
        try {
            cal.setTime(dfWeek.parse(dfWeek.format(cal.getTime())));//剔除日以下的时间
            cal.set(Calendar.DAY_OF_MONTH, 1);
        } catch (ParseException e) {
            log.error(getExceptionMsg(e), e);
            throw new RuntimeException(e);
        }
        return df.format(cal.getTime());
    }
    
    public static String getCurrentYearBegin(String pattern) {
        DateFormat df = new SimpleDateFormat(pattern);
        Calendar cal = Calendar.getInstance();
        DateFormat dfWeek = new SimpleDateFormat("yyyyMMdd");
        try {
            cal.setTime(dfWeek.parse(dfWeek.format(cal.getTime())));//剔除日以下的时间
            cal.set(Calendar.DAY_OF_YEAR, 1);
        } catch (ParseException e) {
            log.error(getExceptionMsg(e), e);
            throw new RuntimeException(e);
        }
        return df.format(cal.getTime());
    }
    
   
    /**
     * 格式化数值，根据输入的模式
     * 
     * @param value
     * @param pattern
     * @return
     */
    public static String formatNumber(double value, String pattern) {
        NumberFormat nf = new DecimalFormat(pattern);
        return nf.format(value);
    }
    
    /**
     * 根据经纬度，获取两点间的距离
     *    
     * @param lng1 经度
     * @param lat1 纬度
     * @param lng2
     * @param lat2
     * @return
     */
    public static double distanceByLngLat(double lng1, double lat1, double lng2, double lat2) {
        double radLat1 = lat1 * Math.PI / 180;
        double radLat2 = lat2 * Math.PI / 180;
        double a = radLat1 - radLat2;
        double b = lng1 * Math.PI / 180 - lng2 * Math.PI / 180;
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1)
                * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * 6378137.0;// 取WGS84标准参考椭球中的地球长半径(单位:m)
        s = Math.round(s * 10000) / 10000;

        return s;
    }
}